package com.dht.xiao.jianye.base.serialport.syncservices;

import android.os.Handler;
import android.os.Looper;
import android.os.SystemClock;

import com.dht.xiao.jianye.base.exception.ApiException;
import com.dht.xiao.jianye.base.exception.ApiExceptionCode;
import com.dht.xiao.jianye.base.serialport.CmdPack;
import com.dht.xiao.jianye.base.serialport.DataPack;
import com.dht.xiao.jianye.base.serialport.callback.BaseDataCallback;
import com.dht.xiao.jianye.base.serialport.callback.SendResultCallback;
import com.dht.xiao.jianye.base.serialport.log.SerialPortLoggerFactory;
import com.dht.xiao.jianye.base.serialport.syncservices.blockingqueue.BaseQueue;
import com.dht.xiao.jianye.base.serialport.syncservices.blockingqueue.Priority;
import com.dht.xiao.jianye.base.serialport.utils.ByteUtil;
import com.dht.xiao.jianye.dlclogfile.LogFileUtil;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.OutputStream;

/**
 * @author :      fangbingran
 * @aescription : todo(这里用一句话描述这个类的作用)
 * @date :        2019/06/06  12:22
 */
public class CmdTask extends BaseQueue {
    private SendResultCallback mSendResultCallback;
    private CmdPack mCmdPack;
    private BaseDataCallback mBaseDataCallback;
    private BufferedInputStream mBufferedInputStream;
    private OutputStream mOutputStream;
    private Handler handler  ;

    public CmdTask(@Priority int priority, SendResultCallback mSendResultCallback, CmdPack mCmdPack, OutputStream outputStream,
                   BufferedInputStream bufferedInputStream, BaseDataCallback baseDataCallback) {
        this.mSendResultCallback = mSendResultCallback;
        this.mCmdPack = mCmdPack;
        mBufferedInputStream = bufferedInputStream;
        mOutputStream = outputStream;
        this.mBaseDataCallback = baseDataCallback;
        handler = new Handler(Looper.getMainLooper()) ;
        setPriority(priority);
    }

    @Override
    public void runTask() {
        boolean isSend = sendData();
        if (!isSend) {
            return;
        }
        boolean isRunning = true;

        int size;
        // 记录一下发送后的时间，用来判断接收数据是否超时
        long sendTime = System.currentTimeMillis();
        long waitTime = 0;
        DataPack dataPack = null;
        while (isRunning) {

            try {

                if (mBufferedInputStream.available() > 0) {
                    // 更新一下接收数据时间
                    waitTime = System.currentTimeMillis();
                    byte[] received = new byte[2048];
                    size = mBufferedInputStream.read(received);
                    dataPack = mBaseDataCallback.checkData(received, size);
                    if (dataPack != null) {
                        //命令码
                        if (mCmdPack.getCheckCommand() == null || mCmdPack.getCheckCommand().size() == 0) {
                            handler.post(new Runnable() {
                                @Override
                                public void run() {
                                    if (mSendResultCallback != null) {
                                        LogFileUtil.getInstance().addLog("248的校验命令不能为空,请设置CmdPack中的checkCommand");
                                        mSendResultCallback.onFailed(new ApiException(ApiExceptionCode.SERIAL_PORT_ERROR,
                                                "248的校验命令不能为空,请设置CmdPack中的checkCommand"));
                                    }
                                }
                            });

                            return;
                        }
//                        if (mCmdPack.getCheckCommand().size() > 1) {
//                            if (mSendResultCallback != null) {
//                                mSendResultCallback.onFailed(new ApiException(ApiExceptionCode.SERIAL_PORT_ERROR,
//                                        "248的校验命令不能超过一个,checkCommand:" + mCmdPack.getCheckCommands()));
//                            }
//                            return;
//                        }
                        String command = ByteUtil.bytes2HexStr(mCmdPack.getCheckCommand().get(0));
                        String readCommand = ByteUtil.bytes2HexStr(dataPack.getCommand());
                        for (int i = 0;i < mCmdPack.getCheckCommand().size();i++){
                            command = ByteUtil.bytes2HexStr(mCmdPack.getCheckCommand().get(i));

                            if (readCommand.equalsIgnoreCase(command)) {
                                final DataPack finalDataPack = dataPack;
                                handler.post(new Runnable() {
                                    @Override
                                    public void run() {
                                        LogFileUtil.getInstance().addLog("获取到结果为:" + finalDataPack);
                                        if (mSendResultCallback != null) {
                                            mSendResultCallback.onSuccess(finalDataPack);
                                        }
                                    }
                                });

                                return;
                            }
                        }
                        final DataPack finalDataPack1 = dataPack;
                        final String finalCommand = command;
                        handler.post(new Runnable() {
                            @Override
                            public void run() {
                                LogFileUtil.getInstance().addLog("命令码不同,获取到结果为:" + finalDataPack1.toString() + "--校验命令码:" + finalCommand);
                                if (mSendResultCallback != null) {
                                    mSendResultCallback.onFailed(new ApiException(ApiExceptionCode.SERIAL_PORT_ERROR,
                                            "命令码不同,获取到结果为:" + finalDataPack1.toString() + "--校验命令码:" + finalCommand));
                                }
                            }
                        });


                        return;
                    }
                } else {
                    // 暂停一点时间，免得一直循环造成CPU占用率过高
                    SystemClock.sleep(1);
                }
                // 检查释放超时
                boolean isTimeOut = isTimeOut(sendTime, waitTime);
                if (isTimeOut) {
                    handler.post(new Runnable() {
                        @Override
                        public void run() {
                            LogFileUtil.getInstance().addLog("读取超时");
                            if (mSendResultCallback != null) {
                                mSendResultCallback.onFailed(new ApiException(ApiExceptionCode.SERIAL_PORT_READ_OUT_TIME_ERROR, "读取超时"));
                            }
                        }
                    });

                    return;
                }
            } catch (final IOException e) {
                handler.post(new Runnable() {
                    @Override
                    public void run() {
                        if (mSendResultCallback != null) {
                            mSendResultCallback.onFailed(new ApiException(ApiExceptionCode.SERIAL_PORT_ERROR, e.toString()));
                        }
                    }
                });

                isRunning = false;
            }
        }
    }

    private boolean isTimeOut(long sendTime, long waitTime) {
        // 表示一直没收到数据
        if (waitTime == 0) {
            long sendOffset = Math.abs(System.currentTimeMillis() - sendTime);
            return sendOffset > mCmdPack.getSendOutTime();
        } else {
            // 有接收到过数据，但是距离上一个数据已经超时
            long waitOffset = Math.abs(System.currentTimeMillis() -waitTime);
            return waitOffset > mCmdPack.getWaitOutTime();
        }
    }

    private boolean sendData() {
        try {
            SystemClock.sleep(100);
            SerialPortLoggerFactory.info("发送码:" + ByteUtil.bytes2HexStr(mCmdPack.getSendData()));
            LogFileUtil.getInstance().addLog("发送码:" + ByteUtil.bytes2HexStr(mCmdPack.getSendData()));
            mOutputStream.write(mCmdPack.getSendData());
        } catch (IOException e) {
            if (mSendResultCallback != null) {
                mSendResultCallback.onFailed(new ApiException(ApiExceptionCode.SERIAL_PORT_ERROR, "硬件错误:" + e.toString()));
            }
            return false;
        }
        return true;
    }
}
